package main

import (
	"context"
	"fmt"
	"log"
	"log/slog"
	"net/http"
	"os"
	"os/signal"
	"student_api/internal/config"
	"student_api/internal/http/handlers/student"
	"student_api/internal/storage/sqlite"
	"syscall"
	"time"
)

// main 函数是程序的入口点，负责初始化配置、设置路由、启动服务器以及优雅关闭
func main() {
	// 打印欢迎信息
	fmt.Println("welcome to students api")

	// 加载配置文件，使用 MustLoad 函数确保配置加载成功
	cfg := config.MustLoad()

	// 数据库设置
	// 初始化SQLite数据库存储
	storage, err := sqlite.New(cfg)
	// 检查存储初始化是否出错
	if err != nil {
		log.Fatal(err)
	}

	// 记录存储初始化成功的结构化日志
	slog.Info("storage initialized",
		slog.String("env", cfg.Env),     // 当前运行环境（如dev/prod）
		slog.String("version", "1.0.0"), // 应用版本号
	)

	// 创建HTTP请求多路复用器，用于路由请求到相应的处理器
	router := http.NewServeMux()

	// 注册学生相关的路由处理器，将 POST /api/students 请求映射到 student.New() 处理器
	router.HandleFunc("POST /api/students", student.New(storage))
	router.HandleFunc("GET /api/students/{id}", student.GetByID(storage))
	router.HandleFunc("GET /api/students", student.GetList(storage))

	// 创建HTTP服务器实例，配置监听地址和请求处理器
	server := http.Server{
		Addr:    cfg.Addr, // 从配置中获取监听地址
		Handler: router,   // 使用上面创建的多路复用器
	}

	// 记录服务器启动日志，包含监听地址信息
	slog.Info("server started -> ", slog.String("address", server.Addr))

	// --- 信号处理机制，用于优雅关闭服务器 ---
	// 创建系统信号通道，缓冲区大小为1，用于接收中断信号
	done := make(chan os.Signal, 1)

	// 设置信号通知，将指定的系统信号发送到 done 通道
	signal.Notify(
		done,            // 接收信号的通道
		os.Interrupt,    // 中断信号（如 Ctrl+C）
		syscall.SIGINT,  // 终端中断信号
		syscall.SIGTERM, // 终止信号（如 kill 命令）
	)

	// 启动 goroutine 异步运行 HTTP 服务器，避免阻塞主协程
	go func() {
		// 启动服务器，开始监听并处理HTTP请求
		err := server.ListenAndServe()
		if err != nil && err != http.ErrServerClosed {
			// 如果启动失败且不是因为正常关闭，记录致命错误并退出
			log.Fatal("failed to start server")
		}
	}()

	// 阻塞主 goroutine，等待中断信号（如 Ctrl+C）
	<-done

	// 记录服务器关闭日志
	slog.Info("shutting down the server")

	// 创建一个5秒超时的上下文，用于控制服务器关闭的最大等待时间
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	// 延迟执行取消函数，确保在函数退出时释放上下文资源
	defer cancel()

	// 使用上下文优雅关闭HTTP服务器，等待现有连接处理完成
	if err := server.Shutdown(ctx); err != nil {
		// 如果关闭过程中发生错误，记录错误日志
		slog.Error("failed to shutdown server", slog.String("error", err.Error()))
	}

	// 记录服务器成功关闭的信息日志
	slog.Info("server shutdown successfully")
}
